package main

import (
	"fmt"
	"math/rand"
	"time"
)

func main() {
	/*
		分支语句：if, switch, select
		1.select语句 类似于 switch语句
			但是select语句会随机执行一个可运行的case
			如果没有case可以运行，要看是否有default，如果有就执行default，否则就进入阻塞，直到有case可以运行

		2.select：
			用于多路监听多个通道
			只要监听的通道中有一个状态是可读或可写的，则select 就不会阻塞
			如果监听的通道有多个可读或可写的状态，则 select 随机选择一个处理

		3.扇入（fan in）：将多路通道聚合到一条通道中处理
			eg：select 聚合多条通道服务
		  扇出（fan out）：将一条通道发散到多条通道中处理
			eg：go 关键字启动多个 goroutine 并发处理

		4.通知退出机制：
			关闭 select 监听的某个通道能使 select 立即感知这种通知，然后进行相应的处理
	*/
	ch1 := make(chan int)
	ch2 := make(chan int)

	go func() {
		time.Sleep(3 * time.Second)
		ch1 <- 100
	}()

	go func() {
		time.Sleep(3 * time.Second)
		ch2 <- 200
	}()

	select {
	case num1 := <-ch1:
		fmt.Println("ch1中获取的数据。。。", num1)
	case num2, ok := <-ch2:
		if ok {
			fmt.Println("ch2中读取的数据。。。", num2)
		} else {
			fmt.Println("ch2通道已关闭。。。")
		}
	default:
		fmt.Println("default语句。。。")

	}

	fmt.Println("main...over...")

	//6.通过退出机制
	done := make(chan struct{})
	ch := GenerateInt0(done)
	close(done) //发送通知，告诉生产者停止生成
	fmt.Println(ch)
}

func GenerateInt0(done chan struct{}) chan int {
	ch := make(chan int)
	go func() {
	Lable:
		for true {
			select {
			case ch <- rand.Int():
			case <-done: //增加一路监听，就是对退出通知信号done的监听
				break Lable
			}
		}
		close(ch) //收到通知后关闭通道 ch
	}()
	return ch
}
